﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ThiefRun.Graphics;
using ThiefRun.Environment;
using ThiefRun.Character;
using ThiefRun.Character.Trains;
using Microsoft.Xna.Framework.Input;

namespace ThiefRun.States
{
    public class LevelState : State
    {
        #region Constants
        // Constants
        const int MINUTE = 60;
        const int TIME_LIMIT = 5 * MINUTE;
        const string LEVEL_DIR = "Levels";
        #endregion Constants

        #region Properties
        // Properties
        Player player;
        NPC npc;
        Level level;
        HUD hud;
        double timeLeft;
        protected List<Enemy> enemies;
        protected List<NPC> NPC;

        int numberOfNpc = 5;

        #endregion Properties

        #region Computed Properties
        // Computed Properties
        public double TimeLeft { get { return timeLeft; } }
        public Level currentLevel { get { return level; } }
        public Train TargetTrain
        {
            get
            {
                foreach (Enemy enemy in enemies)
                {
                    // Return the first train found.
                    if (enemy is Train)
                    {
                        return (Train)enemy;
                    }
                }
                return null;
            }
        }
        public Player Player { get { return player; } }

        bool gotPunched = false;

        #endregion

        #region Methods
        // Methods

        #region Constructors
        /// <summary>
        /// Initialize the level stage.
        /// </summary>
        public LevelState(ThiefRunGame game) : base(game)
        {
            Texture2D playerTexture = game.Content.Load<Texture2D>("Sprites");

            hud = new HUD(game, this);
            level = new Level(game.Content, LEVEL_DIR, new Rectangle(0, 35, game.Graphics.GraphicsDevice.Viewport.Width, game.Graphics.GraphicsDevice.Viewport.Height - 50));
            player = new Player(game, this, playerTexture, new Vector2(level.Bounds.Left + 20, level.Bounds.Top + 25), new Vector2(105, 110), Vector2.Zero, new Vector2(5, 5), Color.White, 0);


            NPC = new List<NPC>();

            int positionX = 200;
            int positionY = 200;

            for (int i = 0; i < numberOfNpc; i++)
            {
                positionX += 100;
                npc = new NPC(game, this, playerTexture, new Vector2(positionX, positionY), new Vector2(105, 110), Vector2.Zero, new Vector2(5, 5), Color.White, 0);
                NPC.Add(npc);
            }
            

            timeLeft = TIME_LIMIT;

            // Setup keybindings.
            List<Keys> keys = new List<Keys>();
            keys.Add(Keys.Up);
            keyboardManager.Add(keys, MoveForwardAction);

            keys = new List<Keys>();
            keys.Add(Keys.Down);
            keyboardManager.Add(keys, MoveBackwardAction);

            keys = new List<Keys>();
            keys.Add(Keys.Left);
            keyboardManager.Add(keys, MoveLeftAction);

            keys = new List<Keys>();
            keys.Add(Keys.Right);
            keyboardManager.Add(keys, MoveRightAction);

            keys = new List<Keys>();
            keys.Add(Keys.Space);
            keyboardManager.Add(keys, PunchAction);

            enemies = new List<Enemy>();

            Vector2 velocity = Vector2.Zero;
            velocity.X = level.Bounds.Width / (float)TIME_LIMIT;

            Texture2D trainTexture = game.Content.Load<Texture2D>("train");
            Train train = new Train(game, this, trainTexture, new Vector2(100, 130), new Vector2(200, 25), new Vector2(5, 0), velocity, Color.Red, 1);
            enemies.Add(train);
        }
        #endregion Constructors

        /// <summary>
        /// Draw the current stage.
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="spriteBatch"></param>
        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            level.Draw(gameTime, spriteBatch);
            player.Draw(gameTime, spriteBatch);
            enemies.ForEach(t => t.Draw(gameTime, spriteBatch));
            NPC.ForEach(t => t.Draw(gameTime, spriteBatch));
            hud.Draw(gameTime, spriteBatch);
        }

        /// <summary>
        /// Perform the actions of the current stage.
        /// </summary>
        /// <param name="gameTime"></param>
        /// 

        public override void Update(GameTime gameTime)
        {
            player.Update(gameTime);
            npc.Update(gameTime);
            enemies.ForEach(e => e.Update(gameTime));
            NPC.ForEach(e => e.Update(gameTime));
            level.Collides(player);

            NpcCollision();
            PlayerCollision();
            
            timeLeft -= gameTime.ElapsedGameTime.TotalSeconds;
            base.Update(gameTime);
        }

        public virtual void PlayerCollision()
        {
            for(int i = 0; i < numberOfNpc ; i++)
                if (player.CheckCollision(NPC[i]) && !gotPunched)
                {
                    if (player.linear.position.X < NPC[i].linear.position.X)
                        player.linear.position.X -= 1;

                    if (player.linear.position.X > NPC[i].linear.position.X)
                        player.linear.position.X += 1;

                    if (player.linear.position.Y < NPC[i].linear.position.Y)
                        player.linear.position.Y -= 1;

                    if (player.linear.position.Y > NPC[i].linear.position.Y)
                        player.linear.position.Y += 1;
                }
        }

        public virtual void PunchCollision()
        {
            gotPunched = true;

            for (int i = 0; i < numberOfNpc; i++)
                if (player.CheckCollision(NPC[i]) && gotPunched)
                {
                    NPC.Remove(NPC[i]);
                    numberOfNpc--;
                    gotPunched = false;
                }

            gotPunched = false;

        }

        public virtual void NpcCollision()
        {
            for (int i = 0; i < numberOfNpc; i++)
                if (player.CheckCollision(NPC[i]))
                {
                    if (NPC[i].linear.position.X < player.linear.position.X)
                        NPC[i].linear.position.X -= 5;

                    if (NPC[i].linear.position.X > player.linear.position.X)
                        NPC[i].linear.position.X += 5;

                    if (NPC[i].linear.position.Y < player.linear.position.Y)
                        NPC[i].linear.position.Y -= 5;

                    if (NPC[i].linear.position.Y > player.linear.position.Y)
                        NPC[i].linear.position.Y += 5;

                    timeLeft -= 1;
                }

            for (int u = 0; u < numberOfNpc; u++)
                for (int y = 0; y < numberOfNpc; y++)
                    if (NPC[u].CheckCollision(NPC[y]))
                    {
                        if (u != y)
                        {
                            if (NPC[u].linear.position.X < NPC[y].linear.position.X)
                                NPC[u].linear.position.X -= 2;

                            if (NPC[u].linear.position.X > NPC[y].linear.position.X)
                                NPC[u].linear.position.X += 2;

                            if (NPC[u].linear.position.Y < NPC[y].linear.position.Y)
                                NPC[u].linear.position.Y -= 2;

                            if (NPC[u].linear.position.Y > NPC[y].linear.position.Y)
                                NPC[u].linear.position.Y += 2;
                        }
                    }
        }

        #region Keyboard Actions
        /// <summary>
        /// The action to execute when the escape is pressed.
        /// </summary>
        private void MoveForwardAction() { player.Move(Player.Direction.Up); }
        private void MoveBackwardAction() { player.Move(Player.Direction.Down); }
        private void MoveLeftAction() { player.Move(Player.Direction.Left); }
        private void MoveRightAction() { player.Move(Player.Direction.Right); }
        private void PunchAction() 
        { 
            player.Action(Player.SpecialAction.Punch);
            PunchCollision();
        }
        #endregion Keyboard Actions
        #endregion Methods
    }
}
